/*
 * SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

#![allow(
    dead_code,
    mutable_transmutes,
    non_camel_case_types,
    non_snake_case,
    non_upper_case_globals,
    unused_assignments,
    unused_mut
)]

use libc::{c_char, c_void};
use std::sync::Mutex;

pub type gint8 = i8;
pub type guint8 = u8;
pub type gint64 = libc::c_long;
pub type guint64 = libc::c_ulong;
pub type gsize = libc::c_ulong;
pub type gchar = libc::c_char;
pub type glong = libc::c_long;
pub type gint = libc::c_int;
pub type gboolean = gint;
pub type gulong = libc::c_ulong;
pub type guint = libc::c_uint;
pub type gfloat = libc::c_float;
pub type gdouble = libc::c_double;
pub type gpointer = *mut libc::c_void;
pub type GType = gsize;

// #[link(name = "user")]
#[derive(Copy, Clone)]
#[repr(C)]
pub struct _GValue {
    pub g_type: GType,
    pub data: [C2RustUnnamed; 2],
}
#[derive(Copy, Clone)]
#[repr(C)]
pub union C2RustUnnamed {
    pub v_int: gint,
    pub v_uint: guint,
    pub v_long: glong,
    pub v_ulong: gulong,
    pub v_int64: gint64,
    pub v_uint64: guint64,
    pub v_float: gfloat,
    pub v_double: gdouble,
    pub v_pointer: gpointer,
}
pub type GValue = _GValue;
#[derive(Copy, Clone)]
#[repr(C)]
pub struct _GValueArray {
    pub n_values: guint,
    pub values: *mut GValue,
    pub n_prealloced: guint,
}
pub type GValueArray = _GValueArray;

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(i32)]
pub enum lu_status {
    /* Non-fatal. */
    lu_success = 0,
    lu_warning_config_disabled,

    /* Fatal. */
    lu_error_generic,
    lu_error_privilege,
    lu_error_access_denied,

    /* Data validation errors. */
    lu_error_name_bad,
    lu_error_id_bad,
    lu_error_name_used,
    lu_error_id_used,

    /* Terminal manipulation errors. */
    lu_error_terminal,

    /* File I/O errors. */
    lu_error_open,
    lu_error_lock,
    lu_error_stat,
    lu_error_read,
    lu_error_write,
    lu_error_search,

    /* Initialization or module-loading errors. */
    lu_error_init,
    lu_error_module_load,
    lu_error_module_sym,
    lu_error_module_version,

    /* Since 0.53 */
    lu_error_unlock_empty,

    /* Since 0.56 */
    lu_error_invalid_attribute_value,

    /* Since 0.57 */
    lu_error_invalid_module_combination,

    /* Since 0.60 */
    lu_error_homedir_not_owned,
}

impl lu_status {
    pub fn is_success(&self) -> bool {
        matches!(self, lu_status::lu_success)
    }

    pub fn is_warning(&self) -> bool {
        matches!(self, lu_status::lu_warning_config_disabled)
    }

    pub fn is_error(&self) -> bool {
        !self.is_success() && !self.is_warning()
    }

    pub fn is_fatal(&self) -> bool {
        matches!(
            self,
            lu_status::lu_error_generic
                | lu_status::lu_error_privilege
                | lu_status::lu_error_access_denied
                | lu_status::lu_error_name_bad
                | lu_status::lu_error_id_bad
                | lu_status::lu_error_name_used
                | lu_status::lu_error_id_used
                | lu_status::lu_error_terminal
                | lu_status::lu_error_open
                | lu_status::lu_error_lock
                | lu_status::lu_error_stat
                | lu_status::lu_error_read
                | lu_status::lu_error_write
                | lu_status::lu_error_search
                | lu_status::lu_error_init
                | lu_status::lu_error_module_load
                | lu_status::lu_error_module_sym
                | lu_status::lu_error_module_version
                | lu_status::lu_error_unlock_empty
                | lu_status::lu_error_invalid_attribute_value
                | lu_status::lu_error_invalid_module_combination
                | lu_status::lu_error_homedir_not_owned
        )
    }
}

impl From<i32> for lu_status {
    fn from(value: i32) -> Self {
        match value {
            0 => lu_status::lu_success,
            1 => lu_status::lu_warning_config_disabled,
            2 => lu_status::lu_error_generic,
            3 => lu_status::lu_error_privilege,
            4 => lu_status::lu_error_access_denied,
            5 => lu_status::lu_error_name_bad,
            6 => lu_status::lu_error_id_bad,
            7 => lu_status::lu_error_name_used,
            8 => lu_status::lu_error_id_used,
            9 => lu_status::lu_error_terminal,
            10 => lu_status::lu_error_open,
            11 => lu_status::lu_error_lock,
            12 => lu_status::lu_error_stat,
            13 => lu_status::lu_error_read,
            14 => lu_status::lu_error_write,
            15 => lu_status::lu_error_search,
            16 => lu_status::lu_error_init,
            17 => lu_status::lu_error_module_load,
            18 => lu_status::lu_error_module_sym,
            19 => lu_status::lu_error_module_version,
            20 => lu_status::lu_error_unlock_empty,
            21 => lu_status::lu_error_invalid_attribute_value,
            22 => lu_status::lu_error_invalid_module_combination,
            23 => lu_status::lu_error_homedir_not_owned,
            _ => lu_status::lu_error_generic, // Default to a generic error for unknown values
        }
    }
}

impl From<lu_status> for i32 {
    fn from(status: lu_status) -> Self {
        status as i32
    }
}

#[derive(Copy, Clone)]
#[repr(C)]
pub struct lu_error {
    pub code: lu_status,
    pub string: *mut libc::c_char,
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct lu_prompt {
    pub key: *const libc::c_char,
    pub prompt: *const libc::c_char,
    pub domain: *const libc::c_char,
    pub visible: gboolean,
    pub default_value: *const libc::c_char,
    pub value: *mut libc::c_char,
    pub free_value: Option<unsafe extern "C" fn(*mut libc::c_void) -> ()>,
}

pub type lu_prompt_fn = fn(
    prompts: *mut lu_prompt,      // Pointer to LuPrompt
    count: i32,                   // Integer count
    callback_data: *mut c_void,   // Pointer to callback data (could be any type)
    error: *mut Option<lu_error>, // Double pointer to Option<LuError>
) -> bool; // Return type is boolean (equivalent to gboolean)

#[repr(C)]
#[derive(Debug, Clone)]
pub struct lu_context {
    pub scache: *mut lu_string_cache,
    pub auth_name: *mut libc::c_char,
    pub auth_type: lu_entity_type,
    pub config: gpointer,
    pub prompter: lu_prompt_fn,
    pub prompter_data: gpointer,
    pub module_names: *mut GValueArray,
    pub create_module_names: *mut GValueArray,
    pub modules: *mut GTree,
}
unsafe impl Send for lu_context {}
unsafe impl Sync for lu_context {}

#[repr(C)]
#[derive(Debug)]
pub struct _GTreeNode {
    pub key: gpointer,
    pub value: gpointer,
    pub left: *mut _GTreeNode,
    pub right: *mut _GTreeNode,
    pub balance: gint8,
    pub left_child: guint8,
    pub right_child: guint8,
}
type gconstpointer = *const c_void;
type GTreeNode = _GTreeNode;
type GCompareDataFunc =
    Option<unsafe extern "C" fn(a: gconstpointer, b: gconstpointer, user_data: gpointer) -> gint>;
type GDestroyNotify = Option<unsafe extern "C" fn(data: gpointer)>;

#[repr(C)]
#[derive(Debug)]
pub struct _GTree {
    pub root: *mut GTreeNode,
    pub key_compare: GCompareDataFunc,
    pub key_destroy_func: GDestroyNotify,
    pub value_destroy_func: GDestroyNotify,
    pub key_compare_data: gpointer,
    pub nnodes: guint,
    pub ref_count: gint,
}

type GTree = _GTree;

// Struct definition for GArray
#[repr(C)]
#[derive(Debug)]
pub struct _GArray {
    pub data: *mut gchar, // Pointer to a character array (gchar* in C)
    pub len: guint,       // Length of the array (guint in C)
}

type GArray = _GArray;

type LU_STRING_CACHE_FUNC = fn(arg1: *mut lu_string_cache, arg2: *const c_char) -> *mut c_char;
type LU_STRING_FREE = fn(arg1: *mut lu_string_cache);

#[repr(C)]
#[derive(Debug)]
pub struct lu_string_cache {
    pub tree: *mut GTree,
    //    pub cache: Option<
    //        unsafe extern "C" fn(arg1: *mut lu_string_cache, arg2: *const c_char) -> *mut c_char,
    //   >,
    pub cache: LU_STRING_CACHE_FUNC,
    pub free: Option<LU_STRING_FREE>,
}

// The lu_ent struct
#[repr(C)]
#[derive(Debug)]
pub struct lu_ent {
    pub magic: u32,                  // u_int32_t magic;
    pub entity_type: lu_entity_type, // enum lu_entity_type type;
    pub cache: *mut lu_string_cache, // *mut lu_string_cache cache;
    pub current: *mut GArray,        // *mut GArray current;
    pub pending: *mut GArray,        // *mut GArray pending;
    pub modules: *mut GValueArray,   // *mut GValueArray modules;
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(i32)]
pub enum lu_entity_type {
    /*< private >*/
    lu_invalid = 0,
    /*< public >*/
    lu_user,
    lu_group,
}

impl lu_entity_type {
    pub fn from_i32(value: i32) -> Option<Self> {
        match value {
            0 => Some(lu_entity_type::lu_invalid),
            1 => Some(lu_entity_type::lu_user),
            2 => Some(lu_entity_type::lu_group),
            _ => None,
        }
    }
    #[allow(clippy::wrong_self_convention)]
    pub fn to_i32(&self) -> i32 {
        *self as i32
    }
}

lazy_static::lazy_static! {
    pub static ref progname: Mutex<Option<String>> = Mutex::new(None); // 程序名
    pub static ref passwd_flags: Mutex<i32> = Mutex::new(0); //
    pub static ref username: Mutex<Option<String>> = Mutex::new(None); // 用户名
    pub static ref libuser_ptr: Mutex<Option<lu_context>> = Mutex::new(None);
    pub static ref NEW_PASSWORD: Mutex<Option<String>> = Mutex::new(None);
}

pub fn get_progname_value() -> Option<String> {
    progname.lock().unwrap().clone()
}
pub fn set_progname_value(version: Option<String>) {
    *progname.lock().unwrap() = version;
}

pub fn get_passwd_flags_value() -> Option<i32> {
    let flags = passwd_flags.lock().unwrap();
    Some(*flags)
}
pub fn set_passwd_flags_value(version: Option<i32>) {
    if let Some(value) = version {
        let mut flags = passwd_flags.lock().unwrap();
        *flags = value;
    }
}
pub fn get_username_value() -> Option<String> {
    username.lock().unwrap().clone()
}
pub fn set_username_value(version: Option<String>) {
    *username.lock().unwrap() = version;
}

// 设置 libuser
pub fn set_libuser(context: Option<lu_context>) {
    let mut guard = libuser_ptr.lock().unwrap(); // 获取互斥锁
    *guard = context; // 将 lu_context 存储到 Option 中
}

// 获取 libuser
pub fn get_libuser() -> Option<lu_context> {
    let guard = libuser_ptr.lock().unwrap(); // 获取互斥锁
    guard.clone() // 返回 Option<lu_context> 的克隆
}
// Get the current password (read)
pub fn get_new_password() -> Option<String> {
    NEW_PASSWORD.lock().unwrap().clone()
}

// Set the new password (write)
pub fn set_new_password(version: Option<String>) {
    *NEW_PASSWORD.lock().unwrap() = version;
}

#[cfg(test)]
mod tests {
    use super::*;
    // use std::sync::Mutex;

    #[test]
    fn test_get_progname_value_with_value() {
        // 设置模拟值
        *progname.lock().unwrap() = Some("test_program".to_string());

        // 测试获取值
        assert_eq!(get_progname_value(), Some("test_program".to_string()));
    }

    #[test]
    fn test_get_progname_value_without_value() {
        // 清除模拟值
        *progname.lock().unwrap() = None;

        // 测试无值情况
        assert_eq!(get_progname_value(), None);
    }

    #[test]
    fn test_get_progname_value_thread_safety() {
        // 在多线程环境下测试锁的安全性
        *progname.lock().unwrap() = Some("thread_test".to_string());

        let handle = std::thread::spawn(|| {
            assert_eq!(get_progname_value(), Some("thread_test".to_string()));
        });

        assert!(handle.join().is_ok());
    }

    #[test]
    fn test_set_progname_value_with_some() {
        let test_value = Some("test_value".to_string());
        set_progname_value(test_value.clone());
        assert_eq!(*progname.lock().unwrap(), test_value);
    }

    #[test]
    fn test_set_progname_value_with_none() {
        set_progname_value(None);
        assert_eq!(*progname.lock().unwrap(), None);
    }

    #[test]
    fn test_set_progname_value_thread_safety() {
        let handles: Vec<_> = (0..10)
            .map(|i| {
                std::thread::spawn(move || {
                    set_progname_value(Some(format!("thread_{}", i)));
                })
            })
            .collect();

        for handle in handles {
            handle.join().unwrap();
        }
    }

    #[test]
    fn test_get_default_value() {
        *passwd_flags.lock().unwrap() = 0;
        assert_eq!(get_passwd_flags_value(), Some(0));
    }

    #[test]
    fn test_set_and_get_positive_value() {
        set_passwd_flags_value(Some(10));
        assert_eq!(get_passwd_flags_value(), Some(10));
    }

    #[test]
    fn test_set_and_get_negative_value() {
        set_passwd_flags_value(Some(-5));
        assert_eq!(get_passwd_flags_value(), Some(-5));
    }

    #[test]
    fn test_set_none_value() {
        set_passwd_flags_value(Some(100));
        set_passwd_flags_value(None);
        assert_eq!(get_passwd_flags_value(), Some(100)); // 验证None不会改变原值
    }

    #[test]
    fn test_passwd_flags_thread_safety() {
        *passwd_flags.lock().unwrap() = 0;

        let set_handle = std::thread::spawn(|| {
            set_passwd_flags_value(Some(42));
        });

        let get_handle = std::thread::spawn(|| {
            // Replace the bitwise OR check with separate assertions
            let flags = get_passwd_flags_value();
            assert!(flags == Some(0) || flags == Some(42));
        });

        set_handle.join().unwrap();
        get_handle.join().unwrap();
    }

    #[test]
    fn test_get_default_username() {
        *username.lock().unwrap() = None;
        assert_eq!(get_username_value(), None);
    }

    #[test]
    fn test_set_and_get_username() {
        let test_name = Some("test_user".to_string());
        set_username_value(test_name.clone());
        assert_eq!(get_username_value(), test_name);
    }

    #[test]
    fn test_set_empty_username() {
        set_username_value(Some("".to_string()));
        assert_eq!(get_username_value(), Some("".to_string()));
    }

    #[test]
    fn test_clear_username() {
        set_username_value(Some("old_user".to_string()));
        set_username_value(None);
        assert_eq!(get_username_value(), None);
    }

    #[test]
    fn test_username_thread_safety() {
        *username.lock().unwrap() = None;

        let set_handle = std::thread::spawn(|| {
            set_username_value(Some("thread_user".to_string()));
        });

        let get_handle = std::thread::spawn(|| {
            let name = get_username_value();
            assert!(name.is_none() || name == Some("thread_user".to_string()));
        });

        set_handle.join().unwrap();
        get_handle.join().unwrap();
    }

    #[test]
    fn test_set_and_get_libuser() {
        fn dummy_prompter(
            _prompts: *mut lu_prompt,
            _count: i32,
            _callback_data: *mut c_void,
            _error: *mut Option<lu_error>,
        ) -> bool {
            false
        }
        let test_context = lu_context {
            scache: std::ptr::null_mut(),
            auth_name: std::ptr::null_mut(),
            auth_type: lu_entity_type::lu_invalid,
            config: std::ptr::null_mut(),
            prompter: dummy_prompter,
            prompter_data: std::ptr::null_mut(),
            module_names: std::ptr::null_mut(),
            create_module_names: std::ptr::null_mut(),
            modules: std::ptr::null_mut(),
        };

        set_libuser(Some(test_context));
        let retrieved = get_libuser();
        assert!(retrieved.is_some());
    }

    #[test]
    fn test_set_none_libuser() {
        set_libuser(None);
        assert!(get_libuser().is_none());
    }

    #[test]
    fn test_lu_context_thread_safety() {
        fn dummy_prompter(
            _prompts: *mut lu_prompt,
            _count: i32,
            _callback_data: *mut c_void,
            _error: *mut Option<lu_error>,
        ) -> bool {
            false
        }
        let test_context = lu_context {
            scache: std::ptr::null_mut(),
            auth_name: std::ptr::null_mut(),
            auth_type: lu_entity_type::lu_invalid,
            config: std::ptr::null_mut(),
            prompter: dummy_prompter,
            prompter_data: std::ptr::null_mut(),
            module_names: std::ptr::null_mut(),
            create_module_names: std::ptr::null_mut(),
            modules: std::ptr::null_mut(),
        };

        let set_handle = std::thread::spawn(move || {
            set_libuser(Some(test_context));
        });

        let get_handle = std::thread::spawn(|| {
            let ctx = get_libuser();
            assert!(ctx.is_none() || ctx.is_some());
        });

        set_handle.join().unwrap();
        get_handle.join().unwrap();
    }

    #[test]
    fn test_get_default_password() {
        *NEW_PASSWORD.lock().unwrap() = None;
        assert_eq!(get_new_password(), None);
    }

    #[test]
    fn test_set_and_get_password() {
        let test_pwd = Some("Test@1234".to_string());
        set_new_password(test_pwd.clone());
        assert_eq!(get_new_password(), test_pwd);
    }

    #[test]
    fn test_set_empty_password() {
        set_new_password(Some("".to_string()));
        assert_eq!(get_new_password(), Some("".to_string()));
    }

    #[test]
    fn test_clear_password() {
        set_new_password(Some("OldPwd".to_string()));
        set_new_password(None);
        assert_eq!(get_new_password(), None);
    }

    #[test]
    fn test_new_passwd_thread_safety() {
        *NEW_PASSWORD.lock().unwrap() = None;

        let set_handle = std::thread::spawn(|| {
            set_new_password(Some("ThreadSafePwd".to_string()));
        });

        let get_handle = std::thread::spawn(|| {
            let pwd = get_new_password();
            assert!(pwd.is_none() || pwd == Some("ThreadSafePwd".to_string()));
        });

        set_handle.join().unwrap();
        get_handle.join().unwrap();
    }
}
